自動勉強会 vol.0 ペイントツール作製技術 前半
https://gyazo.com/661ffb98f61efbde611b239a02634189
課題(やるかどうかは自由)
ペイントツール作ったことないけど話に参加したい人用の入門セットとして、課題を2つ作ってあります。やってから参加すると話の内容が入ってきやすいかもです
ペイントツール課題の実装例回答 by hashrock.icon
シンプルな線を描く
this.old = { x: ev.offsetX, y: ev.offsetY } やるやる…… D.icon
Vue2系
GUI初心者なのでナニモワカラナイyamanoku.icon マウス座標のとり方を毎回調べ直しているmiyanokomiya.icon
毛筆風ブラシ
単純にlineWidthを増減させてたのか、なるほどmiyamonz.icondaiiz.icon
マウス離してもdrawが続くのが描きづらい
これをなんとかしようとするといい感じに細くする部分の実装が工夫が要りそう
マウス離したらN秒間かけてだんだん細くなってゆく仕組みにするとどうなのかな mactkg.icon
動かせば描かれて、動かなかったらそのままみたいな感じにすると、うまくはらい(?)が作れるかな
妄想が広がる
マウスイベントの時間を測り始めると実装が辛くなってくる...miyanokomiya.icon
毛筆というよりインクペンぽくなったmiyamonz.icon
解けなかったdaiiz.icon
ペイントツール実装技術(1時間経過済)
線を引く・ブラシの実装
曲線補間 ( Spline / B-Spline / Catmull-Rom / ... ) seanchas_t.iconは3次B-Spline使いがち (打った点を制御点に)
2点から何点でもOK
https://gyazo.com/45cb6a8f35da09da09109a62b0fc336e
手ブレ補正が効く
Bezierに変換できる
便利!odiak.icon
打った点をそのまま制御点にするのか〜
描いたパスの要所要所が尊重されるか、尊重されないか、というので違いがありますよね(何がなんだったか忘れた) mactkg.icon
あ、制御点だ。制御点を通るかどうか
fabricjs-psbrushは三次スプライン曲線だったようです(と、昔の記事に書いてあった) mactkg.icon
与えられた点列に近い、できるだけ少ない点で構成されたベジェ曲線を返す関数
Kakeruを作るときに、フォークして作りましたが、アルゴリズムはよく理解してないですodiak.icon
実装をほぼ変えずに、TypeScript化しただけ
通過点を通りつつ、いい感じの曲線になってくれる?
これもベジエに変換可能
3Dもいける!miyanokomiya.icon
ベジエに変換して描く方法
InstagramのStoryのペンが描き心地良いのだけどなぜか描き心地がいいのだろうnagayama.icon
インク溜まり(端点)
ポインターの滞留時間で見て重みつけたりするのだろうか
気になる
速度でペン幅が変化している
そこに線形じゃない変換をかけるといい感じになるのかなぁ
Google図形描画、SVG出力できるんだよね。あれ内部で何使ってるのか知らないけどベクターでやって PNGやJPEG出力のときにラスターに変換してる
ラスターへの変換ってBlob経由してCanvasに転写してbase64にする感じでやったことはありますが、Googleさんはもっとスマートに??
パス単純化
間引くと角が丸くなっちゃう問題
人物の髪とか
市販ソフトのベクターツールでも角がぬるい感じになってしまう
間引いてスムージング(quadratic curve にする)ことで線が滑らかになる効果もある 同時お絵描きツールを作ってみたときにポイントを間引ききつつ滑らかにするのにquadratic curve使いましたnagayama.icon
角が取れなくてすごい(角度の変化量が多いところは残る)
https://upload.wikimedia.org/wikipedia/commons/thumb/3/30/Douglas-Peucker_animated.gif/440px-Douglas-Peucker_animated.gif
Wikipediaの絵がわかりやすかった mactkg.iconseanchas_t.iconodiak.icon
こういうgifすきmiyanokomiya.iconmactkg.icon
割とヒューリスティックmiyamonz.icon
計算量も抑えつつできそう
インターセクション
懺悔します、ラスターでやってCanvasのcompositeに丸投げしました
ベジェ曲線同士の交差を検知する時は無数の直線に分割して直線同士の交差を探すようにしたり…
あ、まさにそれと同じことをしました!!odiak.icon
ベジェ曲線をN分割してポリラインにして、で交差判定をしました
SVGのブーリアン、Paper.jsのコアにあるぞって書かれてますね
課題1の勢いよく書いても線がカクカクしないバージョン
下図の赤い点が補助点として配列で得られる
https://gyazo.com/abb8d1c340ca6d416f6739e66a68b1fb/raw
pressure の値も補完?してくれるとうれしい…arcatdmz.icon
わかる...daiiz.icon
これブラウザでサポートしてるのすごい! mactkg.iconseanchas_t.iconnagayama.iconmiyamonz.iconhanak1a.iconmiyanokomiya.icon
iOSだと、補完したデータがApple Pencilで取れたりするんですが、それと一緒だ(アプリの話)
そういうのもあって、最近iPadのネイティブアプリ作りたくなってますodiak.icon
お絵かきソフト以外で需要あるのかこれ……(便利) hanak1a.icon
ジェスチャーとか?odiak.icon
あ〜hanak1a.icon
https://gyazo.com/3717f8e4a0a7102c17c6567e7b06a428
Safari...
カスタムブラシ
テクスチャを使ったブラシ
水彩 (色混ぜ/水彩境界…)
色混ぜ→1点1点に分割して、その点で平均色を取ってブラシの色と混ぜ合わせる、はやったことあるseanchas_t.icon
シェーダーなんですね面白いー
プログラマブルにブラシを作ることができる
アニメ機能もついてる。UIがめちゃめちゃよくできていてすごい mactkg.icon
普通のUI部分がとてもきれい
消しゴム実装されている!
やばいすごいmiyanokomiya.iconmiyamonz.icondaiiz.icon
ばくさんだ!!
ただ直線を引く
canvasに頼らない話
ブレゼンハムのアルゴリズムや、独自の実装について
ビットマップの点を全部舐めて、線分から一定距離にある点を全部塗ると、太い線が描けるodiak.icon
処理速度的にも大丈夫そう!hata6502.icon
点と点の距離が短いので!odiak.icon
これは使えなかったって感じだったのかな? imageSmoothingEnabled mactkg.icon
目的が違う。画像を貼り付けるときにピクセル補完をするかというもの
アウトラインに線引いてから中身を埋めるとかできる?miyanokomiya.icon
多角形で輪郭を描いて、ライン単位で塗りつぶす、でやってます
それもありかも
いや、でも下に絵が描いてあると塗りつぶし大変そう
1ドットずつ fillRect してる()
無茶実装感hata6502.icon
ポリゴン(3D)じゃん
太さの変わる曲線も同じ
N-gonを三角形面に分割する処理だ……D.icon
今度は逆方向の難しさ mactkg.icon
この辺わりと3Dの知見がD.icon
パフォーマンス
React+SVGのパフォーマンスが悪かったので、Canvasで再実装した人ですodiak.icon
canvasも、ペンで描いている間はできるだけ再描画しないとかの工夫をした
VDOM+SVGだけでも会が開けそうmiyanokomiya.icon
描画バックエンドをCanvasにしておいて、UIをVDOMでやりました バウンディングボックスの四角は<div>のborderです
これの曲線がCanvasで描画してて、制御点とかのUIがVueですね
Kakeruもそれです!odiak.icon
Griffith Sketchも同じmactkg.icon
Figmaもそんな感じだったようなnagayama.icon
Figmaはなんか異常に頑張ってますよね.... mactkg.icon
右クリックして出てくるContext Menuとかは自作してそうな気がしている
SVGのRectではだめなんです?
foreignObjectのheightを越えられず描画が途切れる という経験
見えなくしたhtml側で描画しておいて高さを測ってsvg側に適用しましょ?(力技)
やっぱこれしかないのか…miyamonz.icon
imgタグで表示しているときにはforeignObject内部のリソースが読み込まれないことを利用した画像+動画
https://apps.daiiz.dev/static/svg-video/video.svg
⇡ 新しいタブで開くと動画になる
外部リソースの読み込み制限回避のためにBase64にするのあるあるD.icon
foreignObjectの面白さは一通り体験できた daiiz.icon
レイヤーたくさん作ったらメモリが足りなくて大変だった時があった mactkg.icon
レイヤータイリングして描いてない部分は確保しないようにしたいけど大変そうseanchas_t.icon
Fabric.js はオブジェクトごとにbounding boxを計算して持っていて、描画キャッシュはbounding boxサイズで作られるので、レイヤー(fabric.Group)をいっぱい作っても、ラスタみたいに全画面サイズ×レイヤー数のメモリを奪われることはないんですよね arcatdmz.icon
それでもストロークごとに fabric.Path みたいなオブジェクトを生成しているとメモリが足りなくなったりします arcatdmz.icon
上で mactkg.icon が書いてる問題は、たしか retina ディスプレイとかでキャッシュの解像度を調整する部分があって、そのあたりのせいだったような… arcatdmz.icon
canvasが多くなりすぎるのもダメなのか…?
とくにmobile safari なんかのCanvasのメモリ制限がしょっぱい
デカすぎんだろ…(テニヌ)
width=0,height=0設定しないと死なないのかなり罠だ…hanak1a.icon
canvas自体をv-ifで消してあとで再出現させたりすると、getContext('2D')からやり直しになってまう問題
Mobile Safariは200MBちょっとしかメモリがなかった
みんなとにかく色々なことと戦っていてすごいnagayama.icon
組み込みシステムだとメモリ厳しくて undo 回数に制限をかけたことがあるhata6502.icon
cで書く(wasm)
やっぱり速いですか?miyanokomiya.icon
デスクトップアプリと遜色ない速度になっている
js>wasmでデータ渡すところがネックになる場合があるって聞いたことはありますね
Rust でも、wasm が絡むとデータ転送かなり難しい……hata6502.icon
js>wasmは座標データだけ渡して、wasm>jsは更新矩形だけ渡す
1フレームで更新がかかる範囲は局所的なので転送コストがボトルネックになることはない
状態(今のツールとか)ってどこに持ってるんですか?
wasm側はコア+内部的なビットマップとしてのキャンバス
VuexやReduxのstoreってコト…!?
いかに独立した処理として切り出すかが難しそうodiak.icon
8bit paint webはA4 600dpiで持っている。えんぴつチャットはA3 600dpi
A4 600dpi !?D.icon
どいうこと??
4961 x 7016
ペイントツールというテーマが総合格闘技すぎる...!miyanokomiya.icon D.icon